package com.jml.aop.demo001;

import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 *jdk代理：代理接口所有的实现方法
 * 		JDK动态代理：其代理对象必须是某个接口的实现，它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理
 *
 *CGLIB代理：代理对象的所有方法
 * 		CGLIB代理：实现原理类似于JDK动态代理，只是它在运行期间生成的代理对象是针对目标类扩展的子类。
 * 		CGLIB是高效的代码生成包，底层是依靠 ASM（开源的Java字节码编辑类库）操作字节码实现的，性能比JDK强
 *
 *expose-proxy ：有时候目标对 内部的自我调用将无法实施切面中的增强,需要加入这个就可以实现
 *
 *proxy-target-class:SpringAOP部分使用JDK动态代理或者CGLIB来为目标对象创建代理(建议尽量使用JDK的动态代理)。
 *	如果被代理的目标对象实现了至少一个接口，则会使用JDK动态代理。所有该目标类型实现的接口都将被代理。
 *	若该目标对象没有实现任何接口，则创建一个 CGLIB代理。
 *	如果你希望强制使用CGLIB代理（例如希望代理目标对象的所有方法，而不只是实现自接口的方法），那也可以。
 *使用CGHLIB代理存在两个问题：
 *	1.无法通知（ advise） Final方法，因为它们不能被覆写。
 *	2.你需要将CGLIB二进制发行包放在classpath下面。
 *
 * 强制使用CGLIB代理需要将<aop:config>的proxy-target-class属性设置为true
 * 		<aop:config proxy-target-class=true>...</aop:config>
 *
 * 当需要使用CGLIB代理和@AspectJ自动代理支持，可以按照以下方式设置<aop:aspectj-autoproxy>的 proxy-target-class属性
 * 		<aop:aspectj-autoproxy proxy-target-class=true>...</aop:aspectj-autoproxy>
 */
@Service
public class AServiceImpl implements AService{

	@Transactional(propagation = Propagation.REQUIRED)
	@Override
	public void a() {
		/**
		 * 在方法a中此处的this指向目标对象，因此调用this.b()将不会执行事务切面，即不会执行事务增强，
		 * 因此b方法的事务定义@Transactional(propagation = Propagation.REQUIRES_NEW)将不会实施，为了解决这个问题，我们可以这样做
		 * <aop:aspectj-autoproxy expose-proxy="true"/>
		 * 然后将以上代码中的this.b()；修改为((AService)AopContext.currentProxy()).b();”即可
		 * 通过以上的修改便可以完成对a,b方法的同时增强
		 */
		this.b();
		//((AService) AopContext.currentProxy()).b();
	}

	@Transactional(propagation = Propagation.REQUIRES_NEW)
	@Override
	public void b() {

	}

}
